package menv

import (
	"flag"
	"gitee.com/dennis-mxx/gcode-common/mexception"
	"github.com/spf13/viper"
	"path"
)

var metadata = &meta{SysParams: viper.New(), ArgsParams: viper.New(), Args: &args{}}

type meta struct {
	SysParams  *viper.Viper
	ArgsParams *viper.Viper
	Args       *args
}

func ReadSysFile(filePath string) {
	dataType := path.Ext(filePath)
	if dataType != "" {
		dataType = dataType[1:]
		if dataType != "toml" && dataType != "json" && dataType != "ini" && dataType != "properties" {
		}
	} else {
		panic(mexception.NewException(mexception.ERROR, "Please select the configuration file in the following format [toml, ini,json,properties]"))
	}
	metadata.SysParams.SetConfigType(dataType)
	metadata.SysParams.SetConfigFile(filePath)
	if err := metadata.SysParams.ReadInConfig(); err != nil {
		panic(mexception.NewException(mexception.ERROR, "reader config file exception"))
	}
}

func Get(name string) any {
	if v := metadata.ArgsParams.Get(name); v != nil && v != "" {
		return v
	}
	if v := metadata.SysParams.Get(name); v != nil && v != "" {
		return v
	}
	return ""
}

func SetSys(key string, value any) {
	metadata.SysParams.Set(key, value)
}
func AppendArgs(name, defaultValue, usage string) {
	metadata.Args.Append(name, defaultValue, usage)
}
func Unmarshal(rawVal interface{}, opts ...viper.DecoderConfigOption) error {
	vip := viper.New()
	for _, item := range metadata.SysParams.AllKeys() {
		v := metadata.SysParams.Get(item)
		if v == nil || v == "" {
			continue
		}
		vip.Set(item, v)
	}
	for _, item := range metadata.ArgsParams.AllKeys() {
		v := metadata.ArgsParams.Get(item)
		if v == nil || v == "" {
			continue
		}
		vip.Set(item, v)
	}
	return vip.Unmarshal(rawVal, opts...)
}

func ParseArgs() {
	metadata.Args.Parse()
	for k, v := range *metadata.Args {
		if v.Value != "" {
			metadata.ArgsParams.Set(k, v.Value)
		}
	}
}

type Arg struct {
	DefaultValue string
	Value        string
	Name         string
	Usage        string
}

type args map[string]*Arg

func (ew *args) Append(name, defaultValue, usage string) {
	if (*ew)[name] != nil {
		panic("duplicate arg >>> " + name)
	}
	(*ew)[name] = &Arg{Name: name, DefaultValue: defaultValue, Usage: usage}
}

func (ew *args) Parse() {
	for k, v := range *ew {
		flag.StringVar(&v.Value, k, v.DefaultValue, v.Usage)
	}
	flag.Parse()
}
